//
//  AppDelegate.m
//  GCDTest
//
//  Created by wangrui on 14-2-27.
//  Copyright (c) 2014年 Ourui. All rights reserved.
//

#import "AppDelegate.h"

@implementation AppDelegate

- (void)UICreate{
    UIView *rt = self.window.rootViewController.view;
    
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 150, 50)];
    label.backgroundColor = [UIColor lightGrayColor];
    label.userInteractionEnabled = YES;
    self.label = label;
    label.center = CGPointMake(rt.bounds.size.width/2, rt.bounds.size.height/2);
    [rt addSubview:label];
    
    UIGestureRecognizer *g = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(gcdSource)];
    [label addGestureRecognizer:g];
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor whiteColor];
    self.window.rootViewController = [UIViewController new];
    [self.window makeKeyAndVisible];
    [self UICreate];
    
    //[self serialQueue];
    //[self concurrentQueue];
    //[self globleQueue];
    //[self setTargetQueue];
    //[self asysn];
    //[self sysn];
    //[self deadlock];
    //[self group];
    //[self apply];
    //[self barriar];
    //[self semaphore];
    [self gcdAfter];
    
    return YES;
}

- (void)serialQueue{
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.serialqueue", DISPATCH_QUEUE_SERIAL);
    
    //按顺序输出 one，two，three，four
    //是在同一个线程里执行的，任务按照先进先出
    dispatch_async(queue, ^{
        NSLog(@"one:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"two:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"three:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"four:%@",[NSThread currentThread]);
    });
}

- (void)concurrentQueue{
    //自己创建concurrentQueue
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.serialqueue", DISPATCH_QUEUE_CONCURRENT);
    
    //顺序乱了,并发执行的
    //设置断点和打印的结果都可以看到:任务被分派到不同的线程执行了，至于分派给多少个线程执行是gcd根据资源决定的
    dispatch_async(queue, ^{
        NSLog(@"one:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"two:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"three:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"four:%@",[NSThread currentThread]);
    });
}

- (void)globleQueue{
    //globleQueue 也是 concurrentQueue, 结果和上面的 concurrentQueue 一样
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue, ^{
        NSLog(@"one:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"two:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"three:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"four:%@",[NSThread currentThread]);
    });
}

- (void)setTargetQueue{
    dispatch_queue_t globle = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.target", DISPATCH_QUEUE_SERIAL);
    
    //依然是分派到一个线程，先进先出。 实际上serialqueue默认就是分派到glole queue上面的
    dispatch_set_target_queue(queue, globle);
    dispatch_async(queue, ^{
        NSLog(@"one:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"two:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        for (int i=0; i<10000; i++) {
            NSLog(@"process long task");
        }
        NSLog(@"three:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"four:%@",[NSThread currentThread]);
    });
}

- (void)asysn{
    //异步立即返回，不会阻塞线程
    //先输出 retrun now
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.asysn", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        for (int i=0; i<3000; i++) {
            NSLog(@"process long task");
        }
    });
    
    NSLog(@"return now");
}

- (void)sysn{
    
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.asysn", DISPATCH_QUEUE_SERIAL);
    
    //阻塞线程，后输出 return now
    //阻塞的是dispatch_sync函数运行的线程,下面这段代码阻塞的就是主线程
//    dispatch_sync(queue, ^{
//        NSLog(@"%@",[NSThread currentThread]);
//        for (int i=0; i<1000; i++) {
//            NSLog(@"process long task");
//        }
//    });
//    
//    NSLog(@"return now");
    
    
    //下面这段代码先输出 return now
    //如果用的是queue，会造成死锁，原因是serial队列是按FIFO的，那么就会等Block先执行完，而sysn又阻塞了这个Block，所以无法完成
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"root:%@",[NSThread currentThread]);
        
        //sysn 阻塞的是 globleQueue 分派的这个线程
        //没运行完之前不会执行到 dispatch_async函数
        dispatch_sync(queue, ^{
            NSLog(@"sysn:%@",[NSThread currentThread]);
            
            for (int i=0; i<1000; i++) {
                NSLog(@"process long task");
            }
        });
        
        dispatch_async(queue, ^{
            NSLog(@"after sysn:%@",[NSThread currentThread]);
        });
    });
    
    NSLog(@"return now");
}

- (void)deadlock{
    //死锁一
    //避免:DISPATCH_QUEUE_SERIAL 改为 ConcurrentQueue
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.deadlock", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        dispatch_sync(queue, ^{
            NSLog(@"happy,no deadLock!");
        });
    });
    
    
    //死锁二
    //避免:不要同时竞争资源
//    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.deadlock", NULL);
//    dispatch_sync(queue, ^{
//        NSLog(@"%@",[NSThread currentThread]);
//        dispatch_sync(queue, ^{
//            NSLog(@"happy,no deadLock!");
//        });
//    });
    
}

- (void)group{
    //group 对所有队列都有效
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.group", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"one:%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"two,%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, queue, ^{
        for (int i=0; i<1000000000; i++) {
            
        }
        NSLog(@"three:%@",[NSThread currentThread]);
    });
    
    //阻塞dispatch_group_wait函数调用的当前线程,这里是主线程。后输出block compete
    //dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    //NSLog(@"block compete");
    
    //不阻塞主线程，在其他线程运行Block，先输出 block compete
    dispatch_group_notify(group, queue, ^{
        NSLog(@"notify:%@",[NSThread currentThread]);
    });
    NSLog(@"block compete");
}

- (void)apply{
    //下面的这段代码，输出不安顺序，Block是在不同的线程执行的,可以利用多核的性能加快运算
//    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.apply", DISPATCH_QUEUE_CONCURRENT);
//    dispatch_apply(100, queue, ^(size_t idx) {
//        NSLog(@"%zu:%@",idx,[NSThread currentThread]);
//    });
    
    //DISPATCH_QUEUE_SERIAL则是按顺序输出，只有一个线程
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.apply", DISPATCH_QUEUE_SERIAL);
    dispatch_apply(100, queue, ^(size_t idx) {
        NSLog(@"%zu:%@",idx,[NSThread currentThread]);
    });
    
    //后输出apply. dispatch_apply 阻塞 dispatch_apply调用的线程，这里是主线程。也就是apply执行完所有Block才返回
    NSLog(@"apply complete");
}

- (void)barriar{
    //只对自己创建的DISPATCH_QUEUE_CONCURRENT有意义
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.apply", DISPATCH_QUEUE_CONCURRENT);
    
    //globle queue 无效果
    //dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue,^{
        NSLog(@"one:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue,^{
        NSLog(@"two:%@",[NSThread currentThread]);
        for (int i=0; i<1000; i++) {
            NSLog(@"precess two");
        }
    });
    
    //必须等到前两个task执行完（前两个开始顺序不一定），才执行这个，这个执行完才执行下一个
    dispatch_barrier_async(queue, ^{
        for (int i=0; i<100; i++) {
            NSLog(@"barrier task");
        }
        NSLog(@"barrier:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue,^{
        NSLog(@"three:%@",[NSThread currentThread]);
    });
}

- (void)semaphore{
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.semaphore", DISPATCH_QUEUE_CONCURRENT);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(queue, ^{
        for (int i=0; i<1000; i++) {
            NSLog(@"task");
        }
        
        dispatch_semaphore_signal(semaphore);//+1
    });
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//-1 如果信号量小于0,阻塞当前线程
    NSLog(@"thread recive semaphore and continue");//后输出
}

- (void)gcdAfter{
    dispatch_queue_t queue = dispatch_queue_create("com.wangrui.semaphore", DISPATCH_QUEUE_CONCURRENT);
    //dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        for (int i=0; i<2000; i++) {
            NSLog(@"normal process:%@",[NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i=0; i<2000; i++) {
            NSLog(@"concurrent process:%@",[NSThread currentThread]);
        }
    });
    
    //dispath_after分配到到的队列有任务在执行时，必须等待前面的所有任务执行完。
    //上述的队列是自己创建的队列而不是全局并发队列,全局队列时会打断其运行，任务会有交替执行的情况
    //还可以看到有after之后，gcd都会把任务分配到一个线程里做
    /*
        2014-02-27 15:22:38.851 GCDTest[2270:3907] after Block process:<NSThread: 0x8b68530>{name = (null), num = 1}
        2014-02-27 15:22:38.852 GCDTest[2270:1303] normal process:<NSThread: 0x8b68530>{name = (null), num = 1}
        2014-02-27 15:22:38.852 GCDTest[2270:3907] after Block process:<NSThread: 0x8b68530>{name = (null), num = 1}
        2014-02-27 15:22:38.852 GCDTest[2270:1303] normal process:<NSThread: 0x8b68530>{name = (null), num = 1}
     */
    double delayInSeconds = 0.3;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, queue, ^(void){
        for (int i=0; i<2000; i++) {
            NSLog(@"after Block process:%@",[NSThread currentThread]);
        }

    });
    
    //after是异步的,最先输出下面的；
    NSLog(@"retrun now");
}

- (void)gcdSource{
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_event_handler(source, ^{
        unsigned long v = dispatch_source_get_data(source);
        self.label.text = [NSString stringWithFormat:@"%ld",v];
    });
    
    dispatch_resume(source);
    
    //dispatch_queue_t queue = dispatch_queue_create("com.wangrui.source", DISPATCH_QUEUE_CONCURRENT);
    //dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    int delta = [self.label.text intValue];
    dispatch_source_merge_data(source, ++delta);
}

//cycle
- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end
